﻿(function(window){
var 
	moolu3d = function(){
		
		return new mu3d(Array.prototype
						.slice.apply(arguments));
	},
	
	mu3d = function(arryConfig){
		this._init(arryConfig);
		this._initMode();
		if(this._support){
			this._initContainer();
		}else{
			this.onError('not support');
		}
	};
	
mu3d.prototype = {
	_init : function(params){
		var 
			cfg = {},
			len = params.length,
			p, param;
			
		for(var i=1; i<len; i++){
		    
			param = params[i];
			switch(typeof param){
				
				case 'number':
				
					break;
				case 'string':
				
					break;
				case 'function':
				
					break;
				case 'object':
				
					for(p in param){
						cfg[p] = param[p];
					}
			}
		}
		
		var container = params[0];
		
		this._container = container;
		this._clientWidth = container.clientWidth;
		this._clientHeight = container.clientHeight;
		this._support = false;
		this._layers = {};
		this._invalid = [];
		this._show = function(){};
		
		var opt = this._setOptions(cfg);
		
		this.fixedFar = opt.fixedFar;
		this._x = opt.x;
		this._y = opt.y;
		this._z = opt.z;
		this._r = opt.r;
		this._getScale = opt.getScale;
		this.onError = opt.onError;
		
		$$OBEA.selfe.fireEvent(this, 'init');
	},
	
	_setOptions : function(options){
		this.options = {
			mode : 'css3|zoom|base',
			x : 0,
			y : 0,
			z : 0,
			r : 0,
			fixedFar : false,
			getScale : function(z){return 1 - z/1000;},
			onError : function(err){}
		};
		return $$OBEA.extend(this.options, options || {});
	},
	
	_initMode : function(){
		var modes = mu3d.modes;
		this._support = $$OBEA.some(
		this.options.mode.toLowerCase().split('|'), 
		function(mode){
			
			mode = modes[mode];
			if(mode && mode.support){
				this._show = mode.show;
				return true;
			}
		}, this);
	},
	
	_initContainer : function(){
		var 
			container = this._container,
			style = container.style,
			position = $$OBEA.getStyle(container, 'position');
		
		this._style = {
			'position' : style.position,
			'overflow' : style.overflow
		};
		
		if(position != 'relative' && position != 'absolute'){
			style.position = 'relative';
		}
		
		style.overflow = 'hidden';
		$$OBEA.selfe.fireEvent(this, 'initContainer');
	},
	
	show : function(){
		
		if(!this._support){
			this.onError('not support');
			return;
		}
		
		$$OBEA.forEach(this._layers, function(layer, z){
			this._showLayer(z * 1);
		}, this);
	},
	
	_showLayer : function(z){
		var 
			layer = this._layers[z],
			scale = this._getScale(z + this._z);
		
		if(scale<=1 && scale>0){
			var 
				moveScale = this.fixedFar ? scale : (1 - scale);
			
			this._show(layer, scale, 
						this._x * moveScale, this._y * moveScale);
			layer.style.visibility = 'visible';
		}else{
			layer.style.visibility = 'hidden';
		}
	},
	
	add : function(src, options){
		
		if(!this._support){
			this.onError('not support');
			return;
		}
		
		var 
			img = new Image(),
			opt = options || {},
			oThis = this;
		
		function load(){
			this.onload = null;
			oThis._load(this, opt);
		}
		
		function error(){
			oThis.onError('err image');
		}
		
		img.onload = load;
		img.onerror = error;
		img.src = src;
		
		return {
			img : img,
			src : src,
			options : opt,
			show : function(){
				oThis._remove(img);
				img.onload = load;
				img.src = this.src;
			},
			remove : function(){
				oThis._remove(img);
			}
		}
	},
	
	_remove : function(img){
		var 
			z = img._z,
			layer = this._layers[z];
		
		if(layer && img.parentNode == layer){
			layer.removeChild(img);
			if(!--layer._count){
				delete this._layers[z];
				this._invalid.push(this._container.removeChild(layer));
			}
		}
	},
	
	_load : function(img, options){
		var 
			opt = $$OBEA.extend({
				x : 0,
				y : 0,
				z : 0,
				width : 0,
				height : 0,
				scaleW : 1,
				scaleH : 1
			}, options || {}),
		
			clientWidth = this._clientWidth,
			clientHeight = this._clientHeight,
			width = opt.width || img.width * opt.scaleW,
			height = opt.height || img.height * opt.scaleH,
			z = img._z = opt.z;
			
		img.style.cssText = 
		'position:absolute;border:0;padding:0;margin:0;' +
		'-ms-interpolation-mode:nearest-neighbor;' +
		'z-index:' + (99999 - z) + ';width:' + width + 'px;height:' +
		 height + 'px;' + 'left:' + 
		(((clientWidth - width) / 2 + opt.x) / clientWidth * 100).toFixed(5) + 
		'%;top:' + 
		((clientHeight - height - opt.y) / clientHeight * 100).toFixed(5) +
		'%;';
		
		this._insertLayer(img, z);
		this._showLayer(z);
	},
	
	_insertLayer : function(img, z){
		var layer = this._layers[z];
		if(!layer){
			layer = this._invalid.pop();
			if(!layer){
				layer = document.createElement('div');
				layer.style.cssText = 
				'position:absolute;border:0;padding:0;margin:0;' +
				'left:0;top:0;visibility:hidden;background:transparent;' +
				'width:' + this._clientWidth + 
				'px;height:' + this._clientHeight + 'px';
			}
			if($$OBEA.browser.ie6 || $$OBEA.browser.ie7){
				layer.style.zIndex = 999999 - z;
			}
			layer._count = 0;
			layer._z = z;
			this._layers[z] = this._container.appendChild(layer);
		}
		layer._count++;
		layer.appendChild(img);
	},
	
	reset : function(){
		var opt = this.options;
		this._x = opt.x;
		this._y = opt.y;
		this._z = opt.z;
		this._r = opt.r;
		this.show();
	},
	
	destroy : function(){
		$$OBEA.selfe.fireEvent(this, 'destroy');
		
		var container = this._container;
		$$OBEA.setStyle(container, this._style);
		
		$$OBEA.forEach(this._layers, function(layer){
			layer.innerHTML = '';
			container.removeChild(layer);
		});
		
		this._container = this._invalid = 
		this._layers = this._style = this._support = null;
	}
};


mu3d.modes = function(){
	var 
		unit = $$OBEA.browser.firefox ? 'px' : '',
		css3Transform;
	
	return {
		css3 : {
			support : function(){
				var style = document.createElement('div').style;
				return $$OBEA.some(
					['transform', 'MozTransform', 'webkitTransform', 'OTransform'],
					function(css){
						if(css in style){
							css3Transform = css;
							return true;
						}
					}
				);
			}(),
			show : function(layer, scale, x, y){
				var 
					Cos = Math.cos(this._r),
					Sin = Math.sin(this._r);
				
				layer.style.zIndex = 99999 - layer._z;
				layer.style[css3Transform] = 'matrix('
					+ (Cos * scale).toFixed(5) + ',' + (Sin * scale).toFixed(5) + ','
					+ (-Sin * scale).toFixed(5) + ',' + (Cos * scale).toFixed(5) + ','
					+ Math.round(x) + unit + ',' + Math.round(y) + unit + ')';
			}
		},
		zoom : {
			support : function(){
				return 'zoom' in document.createElement('div').style;
			}(),
			show : function(layer, scale, x, y){
				var 
					style = layer.style,
					MAX = Number.MAX_VALUE,
					opScale = 1 - scale,
					left = this._clientWidth * opScale / 2 + x,
					top = this._clientHeight * opScale / 2 + y;
					
					if(!$$OBEA.browser.ie6 && !$$OBEA.browser.ie7){
						left /= scale;
						top /= scale;
					}
					
					left = Math.min(MAX, Math.max(-MAX, left)) | 0;
					top = Math.min(MAX, Math.max(-MAX, top)) | 0;
					
					style.zoom = scale;
					style.left = left + 'px';
					style.top = top + 'px';
			}
		},
		base : {
			support : true,
			show : function(layer, scale, x, y){
				var 
					opScale = 1 - scale,
					left = this._clientWidth * opScale / 2 + x,
					top = this._clientHeight * opScale / 2 + y;
				
				$$OBEA.forEach(layer.getElementsByTagName('img'), function(img){
					var 
						original = img._original = img._original || {
							width : img.offsetWidth,
							height : img.offsetHeight,
							left : img.offsetLeft,
							top : img.offsetTop
						};

					$$OBEA.setStyle(img, {
						width : (original.width * scale | 0) + 'px',
						height : (original.height * scale | 0) + 'px',
						left : (original.left * scale + left | 0) + 'px',
						top : (original.top * scale + top | 0) + 'px'
					});
				});
			}
		}
	};
}();

mu3d.prototype._init = function(){
	var 
		init = mu3d.prototype._init,
		MAX = Number.MAX_VALUE,
		methods = {
			'init' : function(){
				var opt = this.options;
				this._mtMinX = opt.mrMinX;
				this._mtMaxX = opt.mrMaxX;
				this._mtMinY = opt.mrMinY;
				this._mtMaxY = opt.mrMaxY;
				this._mtSTART = $$OBEA.bind(start, this);
				this._mtMOVE = $$OBEA.bind(move, this);
				this._mtSTOP = $$OBEA.bind(stop, this);
			},
			'initContainer' : function(){
				$$OBEA.helpe.addEvent(this._container, 
										'mousedown', this._mtSTART);
			},
			'destroy' : function(){
				$$OBEA.helpe.removeEvent(this._container, 
										'mousedown', this._mtSTART);
				this._mtSTOP();
				this._mtSTART = this._mtMOVE = this._mtSTOP = null;
			}
		};
	
	function start(e){
		this._mtX = this._x + e.clientX;
		this._mtY = this._y + e.clientY;
		$$OBEA.helpe.addEvent(document, 'mousemove', this._mtMOVE);
		$$OBEA.helpe.addEvent(document, 'mouseup', this._mtSTOP);
		
		if($$OBEA.browser.ie){
			var container = this._container;
			$$OBEA.helpe.addEvent(container, 'losecapture', this._mtSTOP);
			container.setCapture();
		}else{
			$$OBEA.helpe.addEvent(window, 'blur', this._mtSTOP);
			e.preventDefault();
		}
	}
	
	function move(e){
		this._x = Math.min(this._mtMaxX, 
					Math.max(this._mtMinX, this._mtX - e.clientX));
		this._y = Math.min(this._mtMaxY, 
					Math.max(this._mtMinY, this._mtY - e.clientY));
		this.show();
		window.getSelection ? 
			window.getSelection().removeAllRanges() :
			document.selection.empty();
	}
	
	function stop(){
		$$OBEA.helpe.removeEvent(document, 'mousemove', this._mtMOVE);
		$$OBEA.helpe.removeEvent(document, 'mouseup', this._mtSTOP);
		
		if($$OBEA.browser.ie){
			var container = this._container;
			$$OBEA.helpe.removeEvent(container, 'losecapture', this._mtSTOP);
			container.releaseCapture();	
		}else{
			$$OBEA.helpe.removeEvent(window, 'blur', this._mtSTOP);
		}		
	}
	
	return function(){
		var options = arguments[0][1];
		if(!options || options.mouseTranslate !== false){
				
			$$OBEA.extend(options, {
				mrMinX : -Number.MAX_VALUE,
				mrMaxX : Number.MAX_VALUE,
				mrMinY : -Number.MAX_VALUE,
				mrMaxY : Number.MAX_VALUE
			}, false);
			
			$$OBEA.forEach(methods, function(method, name){
				$$OBEA.selfe.addEvent(this, name, method);
			}, this);
		}
		init.apply(this, Array.prototype.slice.apply(arguments));				
	}
}();

mu3d.prototype._init = function(){
	var 
		init = mu3d.prototype._init,
		mousewheel = $$OBEA.browser.firefox ? 
					'DOMMouseScroll' : 'mousewheel',
		methods = {
			'init' : function(){
				this._mzMin = this.options.mzMin;
				this._mzMax = this.options.mzMax;
				this._mzZoom = $$OBEA.bind(zoom, this);
			},
			'initContainer' : function(){
				$$OBEA.helpe.addEvent(this._container, 
									mousewheel, this._mzZoom);
			},
			'destroy' : function(){
				$$OBEA.helpe.removeEvent(this._container,
									mousewheel, this._mzZoom);
				this._mzZoom = null;
			}
		};
		
		function zoom(e){
			this._z = Math.min(this._mzMax, Math.max(this._mzMin,
			(e.wheelDelta ? -e.wheelDelta : e.detail * 40) + this._z));
			this.show();
			e.preventDefault();
		}
		
		return function(){
			var options = arguments[0][1];
			if(!options || options.mouseZoom !== false){
				$$OBEA.extend(options, {
					mzMin : -Number.MAX_VALUE,
					mzMax : Number.MAX_VALUE
				}, false);
				
				$$OBEA.forEach(methods, function(method, name){
					$$OBEA.selfe.addEvent(this, name, method);
				}, this);
			}
			
			init.apply(this, Array.prototype.slice.apply(arguments));
		}
}();

var 
	imgs, i3D, mode, support,
	container = document.getElementById('idContainer'),
	src = 'o_n1.jpg';

function $$(id){
	return document.getElementById(id);
}

function create(){
	support = true;
	var options = {
		mzMin : -2000,
		mzMax : 2000,
		mrMinX : -300,
		mrMaxX : 300,
		mrMinY : -150,
		mrMaxY : 150,
		r : $$('idRadian').value * Math.PI/180,
		onError : function(err){
			alert(err);
			support = false;
		}
	};
	
	mode && (options.mode = mode);
	i3D && i3D.destroy();
	i3D = moolu3d(container, options);
	imgs = [];
	if(support){
		for(var z=-1000; z<2000; z+=100){
			add(z, -300, 300); add(z, 0, 300); add(z, 300, 300);
			add(z, -300, 150); add(z, 0, 150); add(z, 300, 150);
			add(z, -300, 0); add(z, 0, 0); add(z, 300, 0);
		}
	}
}

function add(z, x, y){
	imgs.push(i3D.add(src, {z:z, x:x, y:y}));
}

$$('idMode').onchange = function(){
	mode = this.value;
	create();
}

$$('idRadian').onchange = function(){
	i3D._r = this.value * Math.PI/180;
	i3D.show();
}

$$('idFixed').onclick = function(){
	if(!i3D.fixedFar){
		i3D.fixedFar = true;
		this.value = '近点固定';
	}else{
		i3D.fixedFar = false;
		this.value = '远点固定';
	}
	i3D.show();
}

$$('idReset').onclick = function(){
	i3D.reset();
}

create();


var 
	id2 = $$('idContainer2'),
	ii3D = moolu3d(id2, {
		mode : 'base',
		fixedFar : true,
		getScale : function(z){
			return 1/(1 + z/300);
		}
	});

add2("Bush2.gif",{z:-200,x:-300});
add2("Bush2.gif",{z:-200,x:300});
add2("Bush2.gif",{z:-600,x:-300});
add2("Bush2.gif",{z:-600,x:300});
add2("Bush2.gif",{z:-1000,x:-300});
add2("Bush2.gif",{z:-1000,x:300});
add2("bim.jpg",{z:1020,scaleW:9,scaleH:.5,y:20});
add2("r13.gif",{z:900});
add2("r46a.gif",{z:800,x:900,y:220});
add2("r8.gif",{z:800,x:-600});
add2("r22.gif",{z:600});
add2("r24.gif",{z:400});
add2("r62.gif",{z:800,y:700});
add2("r5.gif",{z:600,x:-1200,y:300});
add2("r6.gif",{z:600,x:1200,y:300});
add2("r54.gif",{z:100});
add2("r38.gif",{z:350,x:-900});
add2("r50a.gif",{z:300,x:-550});
add2("r41.gif",{z:1000,x:600,y:200});
add2("r48.gif",{z:300,x:900});
add2("r58b.gif",{z:740,x:900,y:-20});
add2("r58b.gif",{z:250,x:900,y:-20});
add2("r63.gif",{z:300,x:-1000});
add2("r63.gif",{z:320,x:650});
add2("r63.gif",{z:980,x:1000});

function add2(src, options){
	var img = ii3D.add('o_' + src, options).img;
	img.onclick = function(){
		ii3D._z = -options.z | 0;
		ii3D._x = -options.x | 0;
		ii3D._y = options.y | 0;
		ii3D.show();
	}
	img.onmouseover = function(){
		this.style.margin = '-1px';
		this.style.border = '1px solid #666';
	}
	img.onmouseout = function(){
		this.style.margin = '0';
		this.style.border = '0';
	}
}

})(window)